<template>
  <div class="heap-sort">
    <h1 class="title">堆排序算法可视化</h1>

    <!-- 添加详细的算法描述 -->
    <div class="algorithm-description">
      <h2 class="section-title">算法描述</h2>
      <div class="description-content">
        <p>堆排序是一种基于二叉堆数据结构的比较排序算法。它利用堆这种数据结构所设计的一种排序算法。</p>
        <p><strong>算法步骤：</strong></p>
        <ol>
          <li>将待排序序列构建成一个大顶堆</li>
          <li>此时，整个序列的最大值就是堆顶的根节点</li>
          <li>将其与末尾元素进行交换，此时末尾就为最大值</li>
          <li>然后将剩余n-1个元素重新构造成一个堆，这样会得到n个元素的次小值</li>
          <li>如此反复执行，便能得到一个有序序列了</li>
        </ol>
        <p><strong>时间复杂度：</strong></p>
        <ul>
          <li>最坏情况：O(n log n)</li>
          <li>最好情况：O(n log n)</li>
          <li>平均情况：O(n log n)</li>
        </ul>
        <p><strong>空间复杂度：</strong> O(1) - 是原地排序算法</p>
      </div>
    </div>

    <div class="control-panel">
      <el-button type="primary" @click="startSorting" :disabled="isSorting">
        <i class="el-icon-video-play"></i> {{ isSorting ? '排序中...' : '开始排序' }}
      </el-button>
      <el-button @click="pauseSorting" :disabled="!isSorting || isPaused">
        <i class="el-icon-video-pause"></i> 暂停
      </el-button>
      <el-button @click="resumeSorting" :disabled="!isPaused">
        <i class="el-icon-caret-right"></i> 继续
      </el-button>
      <el-button @click="resetArray" :disabled="isSorting && !isPaused">
        <i class="el-icon-refresh"></i> 重置
      </el-button>

      <el-slider v-model="speed" :min="100" :max="1000" :step="100" :disabled="isSorting && !isPaused"
        class="speed-slider">
        <template #prefix>
          <i class="el-icon-time"></i>
        </template>
      </el-slider>
    </div>

    <div class="visualization-container">
      <div class="array-container">
        <div v-for="(item, index) in array" :key="index" class="array-bar" :style="{
          height: item * 5 + 'px',
          backgroundColor: activeIndexes.includes(index) ? '#FF6B6B' : '#4ECDC4',
          boxShadow: activeIndexes.includes(index) ? '0 0 10px rgba(255,107,107,0.7)' : 'none'
        }">
          <span class="bar-value">{{ item }}</span>
        </div>
      </div>
    </div>

    <div class="code-section">
      <h2 class="section-title">代码实现</h2>
      <div class="code-container">
        <el-tabs type="border-card" v-model="currentLanguage">
          <el-tab-pane v-for="(_, lang) in codeLanguages" :key="lang" :label="lang" :name="lang">
            <el-button class="copy-btn" @click="copyCode" type="default" :icon="CopyDocument"></el-button>
            <pre><code>{{ codeLanguages[lang] }}</code></pre>
          </el-tab-pane>
        </el-tabs>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref } from 'vue'
import { CopyDocument } from '@element-plus/icons-vue'
import { ElMessage } from 'element-plus'

// 响应式数据
const isSorting = ref(false)
const isPaused = ref(false)
const speed = ref(500)
const sortingPromise = ref(null)
const sortingResolve = ref(null)
const array = ref([])
const activeIndexes = ref([])
const currentLanguage = ref('JavaScript')
const code = ref('')

// 堆排序辅助函数
const heapify = async (arr, n, i) => {
  let largest = i
  const left = 2 * i + 1
  const right = 2 * i + 2

  if (left < n && arr[left] > arr[largest]) {
    largest = left
  }

  if (right < n && arr[right] > arr[largest]) {
    largest = right
  }

  if (largest !== i) {
    activeIndexes.value = [i, largest]
    // 修复错误：将 setTimeout 赋值给 sortingPromise 时，需要保存 resolve 函数
    await new Promise((resolve) => {
      sortingPromise.value = setTimeout(resolve, 1100 - speed.value);
    });

    [arr[i], arr[largest]] = [arr[largest], arr[i]]
    array.value = [...arr]
    await heapify(arr, n, largest)
  }
}

// 堆排序主函数
const heapSort = async (arr) => {
  const n = arr.length

  // 构建最大堆
  for (let i = Math.floor(n / 2) - 1; i >= 0; i--) {
    await heapify(arr, n, i)
  }

  // 一个个从堆顶取出元素
  for (let i = n - 1; i > 0; i--) {
    activeIndexes.value = [0, i]
    await new Promise((resolve) => {
      sortingPromise.value = setTimeout(resolve, 1100 - speed.value);
    });

    [arr[0], arr[i]] = [arr[i], arr[0]]
    array.value = [...arr]
    await heapify(arr, i, 0)
  }
}

// 代码语言定义
const codeLanguages = {
  JavaScript: `function heapSort(arr) {
  let n = arr.length;

  // 构建最大堆
  for (let i = Math.floor(n / 2) - 1; i >= 0; i--) {
    heapify(arr, n, i);
  }

  // 一个个从堆顶取出元素
  for (let i = n - 1; i > 0; i--) {
    [arr[0], arr[i]] = [arr[i], arr[0]];
    heapify(arr, i, 0);
  }
}

function heapify(arr, n, i) {
  let largest = i;
  const left = 2 * i + 1;
  const right = 2 * i + 2;

  if (left < n && arr[left] > arr[largest]) {
    largest = left;
  }

  if (right < n && arr[right] > arr[largest]) {
    largest = right;
  }

  if (largest !== i) {
    [arr[i], arr[largest]] = [arr[largest], arr[i]];
    heapify(arr, n, largest);
  }
}`,
  Java: `public class HeapSort {
  public static void heapSort(int[] arr) {
    int n = arr.length;

    // 构建最大堆
    for (int i = n / 2 - 1; i >= 0; i--) {
      heapify(arr, n, i);
    }

    // 一个个从堆顶取出元素
    for (int i = n - 1; i > 0; i--) {
      int temp = arr[0];
      arr[0] = arr[i];
      arr[i] = temp;
      heapify(arr, i, 0);
    }
  }

  private static void heapify(int[] arr, int n, int i) {
    int largest = i;
    int left = 2 * i + 1;
    int right = 2 * i + 2;

    if (left < n && arr[left] > arr[largest]) {
      largest = left;
    }

    if (right < n && arr[right] > arr[largest]) {
      largest = right;
    }

    if (largest != i) {
      int swap = arr[i];
      arr[i] = arr[largest];
      arr[largest] = swap;
      heapify(arr, n, largest);
    }
  }
}`,
  Python: `def heapify(arr, n, i):
    largest = i
    left = 2 * i + 1
    right = 2 * i + 2

    if left < n and arr[left] > arr[largest]:
        largest = left

    if right < n and arr[right] > arr[largest]:
        largest = right

    if largest != i:
        arr[i], arr[largest] = arr[largest], arr[i]
        heapify(arr, n, largest)

def heap_sort(arr):
    n = len(arr)

    # 构建最大堆
    for i in range(n // 2 - 1, -1, -1):
        heapify(arr, n, i)

    # 一个个从堆顶取出元素
    for i in range(n - 1, 0, -1):
        arr[i], arr[0] = arr[0], arr[i]
        heapify(arr, i, 0)

    return arr`,
  Golang: `func heapSort(arr []int) {
    n := len(arr)

    // 构建最大堆
    for i := n/2 - 1; i >= 0; i-- {
        heapify(arr, n, i)
    }

    // 一个个从堆顶取出元素
    for i := n - 1; i > 0; i-- {
        arr[0], arr[i] = arr[i], arr[0]
        heapify(arr, i, 0)
    }
}

func heapify(arr []int, n, i int) {
    largest := i
    left := 2*i + 1
    right := 2*i + 2

    if left < n && arr[left] > arr[largest] {
        largest = left
    }

    if right < n && arr[right] > arr[largest] {
        largest = right
    }

    if largest != i {
        arr[i], arr[largest] = arr[largest], arr[i]
        heapify(arr, n, largest)
    }
}`,
  C: `void heapify(int arr[], int n, int i) {
    int largest = i;
    int left = 2 * i + 1;
    int right = 2 * i + 2;

    if (left < n && arr[left] > arr[largest]) {
        largest = left;
    }

    if (right < n && arr[right] > arr[largest]) {
        largest = right;
    }

    if (largest != i) {
        int temp = arr[i];
        arr[i] = arr[largest];
        arr[largest] = temp;
        heapify(arr, n, largest);
    }
}

void heapSort(int arr[], int n) {
    // 构建最大堆
    for (int i = n / 2 - 1; i >= 0; i--) {
        heapify(arr, n, i);
    }

    // 一个个从堆顶取出元素
    for (int i = n - 1; i > 0; i--) {
        int temp = arr[0];
        arr[0] = arr[i];
        arr[i] = temp;
        heapify(arr, i, 0);
    }
}`,
  Rust: `fn heap_sort(arr: &mut [i32]) {
    let n = arr.len();

    // 构建最大堆
    for i in (0..n / 2).rev() {
        heapify(arr, n, i);
    }

    // 一个个从堆顶取出元素
    for i in (1..n).rev() {
        arr.swap(0, i);
        heapify(arr, i, 0);
    }
}

fn heapify(arr: &mut [i32], n: usize, i: usize) {
    let mut largest = i;
    let left = 2 * i + 1;
    let right = 2 * i + 2;

    if left < n && arr[left] > arr[largest] {
        largest = left;
    }

    if right < n && arr[right] > arr[largest] {
        largest = right;
    }

    if largest != i {
        arr.swap(i, largest);
        heapify(arr, n, largest);
    }
}`
}

// 初始化数组
const resetArray = () => {
  array.value = Array.from({ length: 10 }, () => Math.floor(Math.random() * 50) + 5)
  activeIndexes.value = []
}

// 复制代码
const copyCode = async () => {
  try {
    await navigator.clipboard.writeText(code.value)
    ElMessage.success('复制成功')
  } catch (err) {
    console.error('复制失败: ', err)
    ElMessage.error('复制失败')
  }
}

// 排序控制
const startSorting = async () => {
  if (isSorting.value) {
    return
  }

  isSorting.value = true
  isPaused.value = false
  const arr = [...array.value]

  await heapSort(arr)

  activeIndexes.value = []
  isSorting.value = false
  isPaused.value = false
  sortingResolve.value = null // 排序完成后清空
}

const pauseSorting = () => {
  if (!isSorting.value) {
    return
  }
  isPaused.value = true
}

const resumeSorting = () => {
  if (!isPaused.value) {
    return
  }
  isPaused.value = false
  if (sortingResolve.value) {
    const resolve = sortingResolve.value
    sortingResolve.value = null
    resolve()
  } else {
    // 如果没有找到resolve函数，强制重新开始排序
    startSorting()
  }
}

// 初始化
resetArray()
</script>

<style scoped>
.heap-sort {
  --bg-color: #ffffff;
  --text-color: #333333;
  --primary-color: #409eff;
  --border-color: #dcdfe6;
  --code-bg: #f5f7fa;
  --bar-bg: #e4e7ed;
  --active-bar-bg: #f56c6c;
  max-width: 100%;
  min-height: 100vh;
  margin: 0;
  padding: 1rem;
  background-color: var(--bg-color);
  color: var(--text-color);
}

.title {
  text-align: center;
  color: var(--text-color);
  margin: 1rem 0;
  font-weight: 500;
  font-size: clamp(1.5rem, 4vw, 2rem);
}

.algorithm-description {
  background: var(--bg-color);
  border-radius: 4px;
  padding: 1rem;
  margin-bottom: 1.5rem;
  border: 1px solid var(--border-color);
}

.description-content {
  line-height: 1.6;
  font-size: clamp(0.9rem, 2vw, 1rem);
}

.control-panel {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: 0.8rem;
  margin-bottom: 1.5rem;
}

.speed-slider {
  width: clamp(150px, 30vw, 250px);
  margin-left: 0.5rem;
}

.visualization-container {
  background: var(--bg-color);
  border-radius: 4px;
  padding: 1rem;
  margin-bottom: 1.5rem;
  border: 1px solid var(--border-color);
}

.array-container {
  display: flex;
  justify-content: center;
  align-items: flex-end;
  height: 250px;
  gap: 0.3rem;
}

.array-bar {
  width: clamp(20px, 4vw, 40px);
  background: var(--bar-bg);
  border-radius: 2px 2px 0 0;
  transition: all 0.3s ease;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  align-items: center;
  border: 1px solid var(--border-color);
}

.array-bar.active {
  background: var(--active-bar-bg);
  border-color: var(--active-bar-bg);
}

.code-container {
  position: relative;
  border-radius: 4px;
  overflow: hidden;
  border: 1px solid var(--border-color);
}

.bar-value {
  margin-bottom: 5px;
  font-size: clamp(0.6rem, 1.5vw, 0.8rem);
}

.copy-btn {
  position: absolute;
  right: 10px;
  top: 10px;
  z-index: 1;
}

pre {
  overflow: auto;
}

@media (max-width: 768px) {
  .quick-sort {
    padding: 0.5rem;
  }

  .control-panel {
    gap: 0.3rem;
    flex-direction: column;
    align-items: stretch;
  }

  .array-container {
    height: 180px;
    gap: 0.2rem;
  }

  .array-bar {
    width: clamp(15px, 3vw, 25px);
  }

  .speed-slider {
    width: 100%;
    margin-left: 0;
  }

  .description-content {
    font-size: 0.8rem;
  }
}
</style>
